package prototype;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

public class ProtoHelper {

    //A lehetseges parancsok
    private static String[] commands = {"loadNetwork", "reset", "switch", "step", "examine", "exit"};

    //Lista a lehetseges parancsokbol a könnyu kereses, indexeles miatt
    private static ArrayList<String> Commands = new ArrayList<String>();

    //Kimeneti fajl
    private static String outFile;
    
    //Fajlba iras? igaz - hamis
    private static boolean toFile;
    
    //Fajlba irashoz
    private static FileOutputStream fileStream;

    //A parancsok hozzaadása a listához
    static {
        for (String ans : commands) {
            Commands.add(ans);
        }
    }

    //Parancs beolvasása az alapértelmezett bemenetről, validálás, végrehajtás indítása
    public static void ReadCommand()
    {
        //Alapertelmezett bemenet
        Scanner n = new Scanner(System.in);
        
        //Aktualis beolvasott parancs
        String actCommand = "";
        
        //Aktualis beolvasott argumentum
        String actArgument = "";

        //exit parancs miatt lehetseges
        while (true) {
            System.out.print("\nCommand: ");
            try {
                //parancs beolvasasa
                String line = n.nextLine();

                //van-e argumentum
                int index = line.indexOf(" ") == -1 ? line.length() : line.indexOf(" ");

                //parancs levagasa a stringbol
                actCommand = line.substring(0, index);
                
                //validalas
                if (!Commands.contains(actCommand)) {
                    System.out.println("// Command not found //");
                    continue;
                }

                //Ezeknel a parancsoknal szükseges az argumentum, különben helytelen
                if (Commands.indexOf(actCommand) == 0 || Commands.indexOf(actCommand) == 2 || Commands.indexOf(actCommand) == 4) {
                    String d = line.substring(line.indexOf(" ") + 1, line.length());
                    if (line.indexOf(" ") == -1 || d.length() == 0) {
                        System.out.println("// Command not found //");
                        continue;
                    }

                    //argumentum
                    actArgument = d;
                }

                //parancsvegzo függveny meghivasa a kiolvasott parancs és argumentum felhasznalasaval
                ExecuteCommand(actCommand, actArgument);

            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            }
        }

    }
    //Ugyanaz, mint a ReadCommand + fajlkezeles
    public static void ReadCommandFromFile(String fileName) {
        File file = new File(fileName);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        DataInputStream dis = null;
        
        //aktualis parancs
        String actCommand = "";
        
        //aktualis argumentum
        String actArgument = "";

        try {
            //create fileinpustream from file
            fis = new FileInputStream(file);
            
            //create bufferedinputstream for faster reading
            bis = new BufferedInputStream(fis);
            
            //create datainputsream
            dis = new DataInputStream(bis);

            //ha nem ures
            while (dis.available() != 0) {
                try {
                    //sor beolvasasa
                    String line = dis.readLine();

                    //van-e argumentum
                    int index = line.indexOf(" ") == -1 ? line.length() : line.indexOf(" ");

                    //parancs levagasa
                    actCommand = line.substring(0, index);
                    //validalas
                    if (!Commands.contains(actCommand)) {
                        System.out.println("// Command not found //");
                        continue;
                    }
                    //Ezeknel a parancsoknal szükseges az argumentum, különben helytelen
                    if (Commands.indexOf(actCommand) == 0 || Commands.indexOf(actCommand) == 2 || Commands.indexOf(actCommand) == 4) {
                        String d = line.substring(line.indexOf(" ") + 1, line.length());
                        if (line.indexOf(" ") == -1 || d.length() == 0) {
                            System.out.println("// Command not found //");
                            continue;
                        }
                        actArgument = d;
                    }
                    //parancsvegzo fuggveny meghivasa a kiolvasott parancs és argumentum felhasznalasaval
                    ExecuteCommand(actCommand, actArgument);

                } catch (Exception ex) {
                    //System.out.println(ex.getMessage());
                }
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }

    //Parancs vegrehajtasa
    private static void ExecuteCommand(String command, String argument) {
        
        //parancsoknak megfelelo esetek
        switch (Commands.indexOf(command)) {

            //loadNetwork
            case 0: {
                try {
                    NetworkLoaderController.loadNetworkFromXMLFile(argument);
                    printDatShit("# The network from " + argument + " successfully loaded.\n");
                } catch (Exception e) {
                    printDatShit("!! The network from " + argument + " could not be loaded !!\n");
                }
                break;

            }

            //reset
            case 1: {
                try {
                    SimulationController.resetSimulation();
                    printDatShit("# Network Reseted.\n");
                } catch (Exception ex) {
                }
                break;
            }

            //switch
            case 2: {
                int id = Integer.valueOf(argument);
                try {
                    //kapcsolo elerese id alapjan
                    Switch sw = (Switch) NetworkLoaderController.getDigitalElement(id);
                    
                    //kapcsolo allitasa
                    sw.stepState();
                    printDatShit("# Switch " + argument + " switched.\n");
                } catch (Exception ex) {
                }
                break;
            }

            //step
            case 3: {
                try {
                    //leptetes
                    SimulationController.stepSimulation();
                    printDatShit("# Network stepped.\n");
                } catch (Exception ex) {
                    printDatShit("!! Network is instable !!\n");
                }
                break;
            }

            //examine
            case 4: {
                try {
                    int id = Integer.valueOf(argument);
                    DigitalElement c = NetworkLoaderController.getDigitalElement(id);
                    printDatShit("# Examining DigitalElement " + argument + "\n");                    
                    printDatShit("\t" + c.getType().toString() + " " + argument + ":\n");

                    //elemnek megfelelo examine
                    switch (c.getType()) {
                        
                        //examine Led
                        case Led: {
                            Led d = (Led) NetworkLoaderController.getDigitalElement(id);
                            //Bemenetek kiirasa
                            for (int i = 0; i < d.inputList.size(); i++) {
                                printDatShit("\t\tInput " + i + ": ");
                                for (Wire input : d.inputList.get(i)) {
                                    printDatShit(input.getDigitalValue().toString());
                                }
                            }
                            //Allapot kiirasa
                            if (d.getState() == Sign.High) {
                                printDatShit("\n\t\tLight: On\n");
                            } else {
                                printDatShit("\n\t\tLight: Off\n");
                            }
                            break;
                        }

                        //examine Generator
                        case Generator: {
                            Generator d = (Generator) NetworkLoaderController.getDigitalElement(id);
                            printDatShit("\t\tPattern: ");
                            
                            //Minta kiirasa
                            for (int i = 0; i < d.getSize(); i++) {
                                printDatShit(d.getPattern(i).toString() + " ");
                            }
                            printDatShit("\n\t\tIndex: " + d.getPatternIndex());

                            //Kimenetek kiirasa
                            for (int i = 0; i < d.outputList.size(); i++) {
                                printDatShit("\n\t\tOutput " + i + ": ");
                                for (Wire output : d.outputList.get(i)) {
                                    printDatShit(output.getDigitalValue().toString());
                                }
                            }
                            printDatShit("\n");
                            break;
                        }

                        //examine Switch
                        case Switch: {
                            Switch d = (Switch) NetworkLoaderController.getDigitalElement(id);

                            //Kimenetek kiirasa
                            for (int i = 0; i < d.outputList.size(); i++) {
                                printDatShit("\t\tOutput " + i + ": ");
                                for (Wire output : d.outputList.get(i)) {
                                    printDatShit(output.getDigitalValue().toString());
                                }
                            }
                            printDatShit("\n");
                            break;
                        }

                        //examine Oscilloscope
                        case Oscilloscope: {
                            Oscilloscope o = (Oscilloscope) NetworkLoaderController.getDigitalElement(id);
                            //bemenetek kiirasa
                            for (int i = 0; i < o.inputList.size(); i++) {
                                printDatShit("\t\tInput " + i + ": ");
                                for (Wire input : o.inputList.get(i)) {
                                    printDatShit(input.getDigitalValue().toString() + "\n");
                                }
                            }
                            printDatShit("\t\tMemory: ");
                            //memoria kiirasa
                            for( int i= 0; i < o.getMemory().size(); i++)
                                    printDatShit(o.getMemory().get(i).toString()+ " ");
                            printDatShit("\n");
                            break;
                            
                        }


                       //all the gates, AND, OR, Inverter, Composit
                        default: {
                            DigitalGate d = (DigitalGate) NetworkLoaderController.getDigitalElement(id);
                            //bemenetek kiirasa
                            for (int i = 0; i < d.inputList.size(); i++) {
                                printDatShit("\t\tInput " + i + ": ");
                                for (Wire input : d.inputList.get(i)) {
                                    printDatShit(input.getDigitalValue().toString() + "\n");
                                }
                            }
                            //kimenetek kiirasa
                            for (int i = 0; i < d.outputList.size(); i++) {
                                printDatShit("\t\tOutput " + i + ": ");
                                for (Wire output : d.outputList.get(i)) {
                                    printDatShit(output.getDigitalValue().toString() + "\n");
                                }
                            }
                            break;
                        }
                    }
                } catch (Exception ex) {
                    printDatShit(ex.getMessage());
                }
                break;
            }

            //exit
            case 5: {
                    try {
                            fileStream.close();
                    } catch (IOException ex) { }
                    System.exit(0);
            }
        }
    }

    //Kimeneti fajl megadasa
    public static void setOutFile(String val) {
        outFile = val;
        try {
            fileStream = new FileOutputStream(new File(outFile));
        } catch (FileNotFoundException ex) {
           
        }
    }

    //Kiiro fuggveny - standard outputra es opcionalisan fajlba
    private static void printDatShit(String dis) {
        System.out.print(dis);

        if (toFile) {
            try {
                fileStream.write(dis.getBytes());
            } catch (IOException ex) {
                //asd
            }
        }
    }

    //Fajlba iras opcio
    public static void setToFile(boolean val) {
        toFile = val;
    }
}
